#include <ll.h>
#include "ut.h"
#include <stdio.h>
#include <string.h>

void run_ll();
void run_aa();
void run_aa_walk();

TestDesc ll_tests[] = {
    { "ll", run_ll },
    { "aa random access", run_aa },
    { "aa walk", run_aa_walk },
    { NULL, NULL }
};

void run_ll() {
    LL *ll = NULL;
    LL *i;
    int c;

    int data[] = { 100, 101, 102, 103 };

    ll_add( &ll, &data[0] );
    ll_add( &ll, &data[1] );
    ll_add( &ll, &data[2] );

    i = ll;
    for (c=2; c >= 0; c--) {
        ASSERT( (i != NULL), "have next" );
        if (i != NULL) {
            ASSERT( (i->obj == &data[c]), "get next" );
            i = i->next;
        }
    }
    
    i = ll_find( ll, &data[3] );
    ASSERT( (i == NULL), "find non-existing" );

    i = ll_find( ll, &data[1] );
    ASSERT( (i != NULL) && (i->obj == &data[1]), "find middle" );

    if (i) {
        ll_remove( &ll, i );
        ASSERT( ll_find( ll, &data[1] ) == NULL, "find removed" );
    }

    ll_remove_obj( &ll, &data[0] );
    ASSERT( ll_find( ll, &data[0] ) == NULL, "find removed 0" );

    c=0;
    for (i=ll; i!=NULL; i=i->next) c++;
    ASSERT( c == 1, "left 1" );

    ll_remove_obj( &ll, &data[2] );
    ASSERT( ll_find( ll, &data[2] ) == NULL, "find removed 2" );

    ASSERT( ll == NULL, "removed all" );

    ll_add( &ll, &data[3] );
    ASSERT( ll != NULL, "add again" );
    
    ASSERT( ll->obj == &data[3], "add 3" );

    ll_destroy(&ll);
}

void run_aa() {
    AA *aa = aa_create();

    aa_set(aa, "key one", (void*)0x101010);
    aa_set(aa, "key two", (void*)0x202020);
    aa_set(aa, "key three", (void*)0x303030);

    ASSERT( (aa_get(aa, "key one") == (void*)0x101010), "aa add/get one" );
    ASSERT( (aa_get(aa, "key three") == (void*)0x303030), "aa add/get three" );
    
    ASSERT( (aa_get(aa, "xnxnxn") == NULL),  "aa get non existent" );
    ASSERT( (aa_get(aa, "key one ") == NULL), "aa_get non existent" );

    aa_remove(aa, "key one");
    ASSERT( (aa_get(aa, "key one") == NULL), "aa get removed" );

    aa_destroy(aa);
}

void run_aa_walk() {
    AA *aa = aa_create();
    int c, i;

    const char *keys[] = { "k1", "k2", "k3" };
    void* values[] = { (void*)0x10, (void*)0x20, (void*)0x30 };
    int khits[] = { 0, 0, 0 };
    int vhits[] = { 0, 0, 0 };
    
    for (i = 0; i < 3; i++) {
        aa_set(aa, keys[i], values[i]);
    }

    const char *key;
    void *value;
    for (c = 0; c < aa_end(aa); c++) {
        key = aa_key(aa, c);
        value = aa_value(aa, c);

        for (i = 0; i < 3; i++) {
            if (strcmp(key, keys[i]) == 0) khits[i]++;
            if (value == values[i]) vhits[i]++;
        }
    }

    ASSERT_EQI( khits[0], 1, "key k1 hits" );
    ASSERT_EQI( khits[1], 1, "key k2 hits" );
    ASSERT_EQI( khits[2], 1, "key k3 hits" );
    ASSERT_EQI( vhits[0], 1, "value 0x10 hits" );
    ASSERT_EQI( vhits[1], 1, "value 0x20 hits" );
    ASSERT_EQI( vhits[2], 1, "value 0x30 hits" );

    aa_destroy(aa);
}
